package com.ml.mall.aspect;

import com.ml.mall.annotation.LogMethodInvokeInformation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Arrays;

/**
 * @description 输出方法执行信息切面
 * @author yx
 * @date 2021/9/24
 * @version 1.0
*/
@Slf4j
@Aspect
@Component
public class LogMethodInvokeInformationAspect {
    @Pointcut(value = "execution(* com.ml.mall..*.*(..)) && @annotation(com.ml.mall.annotation.LogMethodInvokeInformation)")
    public void pointCut(){

    }

    /**
     * 打印方法的执行信息
     * @param joinPoint 切入点
     * @param logAnnotation 日志注解
     * @return
     */
    @Around(value = "@annotation(logAnnotation)", argNames = "joinPoint, logAnnotation")
    public Object logInformation(ProceedingJoinPoint joinPoint, LogMethodInvokeInformation logAnnotation) throws Throwable {
        //获取方法调用信息
        Signature signature = joinPoint.getSignature();//方法
        String methodName = signature.getName();//方法名
        Object[] args = joinPoint.getArgs();//入参
        String declaringTypeName = signature.getDeclaringTypeName();//方法所属类名
        String operation = StringUtils.isEmpty(logAnnotation.value())
                            ? declaringTypeName + "." + methodName : logAnnotation.value();//操作名称

        //输出方法入参信息
        log.info("operation [{}] is executed with args=====[{}]", operation, Arrays.toString(args));

        long startTimeMills = System.currentTimeMillis();
        //执行方法
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            //发生异常直接将异常抛出，输出异常信息
            log.error("operation [{}] throws exception=====[{}]", operation, throwable);
            throw throwable;
        }

        //执行完毕，输出执行时间和返回结果
        long endTimeMills = System.currentTimeMillis();
        long timeBetween = endTimeMills - startTimeMills;
        log.info("operation [{}] is completed and costs=====[{}] ms", operation, timeBetween);
        log.info("operation [{}] returns=====[{}]", operation, result);
        return result;
    }
}
